/*
 * xmega_i2c.c
 *
 *  Created on: 2011/05/08
 *      Author: AKS
 */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include "core/include/aks_processor.h"
#include "core/include/types.h"



/* transmit system */
BOOL I2C_isNACK(void)
{
	return (0==(TWIC.MASTER.STATUS & 0x10)) ? FALSE : TRUE;
}

BOOL I2C_waitForTxDone(void)
{
	while( !(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm) );
	return TRUE;
}


BOOL I2C_waitForRxDone(void)
{
	while( !(TWIC.MASTER.STATUS & TWI_MASTER_RIF_bm) );
	return TRUE;
}


void I2C_stopCondition(void)
{
	TWIC.MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc;
}

BOOL I2C_transmitAddr(BYTE adr)
{
	// send address
	TWIC.MASTER.ADDR = adr;

	// wait for sending
	I2C_waitForTxDone();

	return (FALSE == I2C_isNACK());
}

BOOL I2C_receiveAddr(BYTE adr)
{
	// send address
	TWIC.MASTER.ADDR = adr;

	// wait for sending
	I2C_waitForRxDone();

	return (FALSE == I2C_isNACK());
}


BOOL I2C_transmitByte(BYTE dat)
{
	TWIC.MASTER.DATA = dat;
	I2C_waitForTxDone();

	return (FALSE == I2C_isNACK());
}

BOOL I2C_receiveByte(BYTE *dat, BYTE ack)
{
	I2C_waitForRxDone();

	*dat = TWIC.MASTER.DATA;

	if( ack )
	{
		TWIC.MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc;
	}
	else // nack
	{
		TWIC.MASTER.CTRLC = TWI_MASTER_ACKACT_bm | TWI_MASTER_CMD_STOP_gc;
	}

	return TRUE;
}

/* --------------------------------------------------------
   AKS Processor Interface function
 -------------------------------------------------------- */
/* I2C system function */
BOOL Init_I2C(BYTE ownAddress, WORD clk_KHz)
{
	TWIC.CTRL = 0x00;
	TWIC.MASTER.CTRLA = TWI_MASTER_INTLVL_LO_gc | 0x08; // Enable TWI
	TWIC.MASTER.CTRLB = 0x00;
	TWIC.MASTER.CTRLC;
	TWIC.MASTER.BAUD = 160; // for 100kHz
	TWIC.MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;

    return TRUE;
}

BOOL I2C_transmitBytes(BYTE slaveAdr, BYTE *tx_buf, BYTE tx_len)
{
	BOOL retVal = FALSE;

	if( TRUE == I2C_transmitAddr((slaveAdr << 1) & 0xFE))
	{
		for(BYTE i=0 ; i<tx_len ; i++, tx_buf++)
		{
			if( FALSE == I2C_transmitByte(*tx_buf) )
			{
				break;
			}
		}
		retVal = TRUE;
	}

	I2C_stopCondition();

    return retVal;
}

BOOL I2C_receiveBytes (BYTE slaveAdr, BYTE *tx_buf, BYTE tx_len, BYTE *rx_buf, BYTE rx_len)
{
	BOOL retVal = 0;

	// send target address
	if( TRUE == I2C_transmitAddr((slaveAdr << 1) & 0xFE))
	{
		for(BYTE i=0 ; i<tx_len ; i++, tx_buf++)
		{
			if( FALSE == I2C_transmitByte(*tx_buf))
			{
				break;
			}
		}
		retVal = TRUE;
	}
	else
	{
		return FALSE;
	}

	// restart and reveice data
	if( TRUE == I2C_receiveAddr((slaveAdr << 1) | 0x01) )
	{
		for(BYTE i=0 ; i < rx_len ; i++, rx_buf++ )
		{
			I2C_receiveByte( rx_buf, ((i+1)!=rx_len ? 1:0) );
		}

		retVal = TRUE;
	}
	else
	{
		return FALSE;
	}

	return retVal;
}

